home *** CD-ROM | disk | FTP | other *** search
/ The Very Best of Atari Inside / The Very Best of Atari Inside 1.iso / mint / mntlb20 / lib / malloc.c < prev    next >
C/C++ Source or Header  |  1992-05-15  |  7KB  |  305 lines

  1. /* from the TOS GCC library */
  2. /* malloc, free, realloc: dynamic memory allocation */
  3. /* 5/2/92 sb -- modified for Heat-n-Serve C to accomodate its 16-bit size_t */
  4. /* 5/5/92 sb -- split off realloc() & calloc() to reduce library drag */
  5.  
  6. #include <stddef.h>    /* for size_t */
  7. #include <memory.h>
  8. #include <string.h>
  9. #include <assert.h>
  10. #include "lib.h"
  11.  
  12. extern long _stksize;
  13. extern void *_sbrk();
  14.  
  15. /* minimum chunk to ask OS for */
  16. static size_t MINHUNK =    4096L;    /* default */
  17. static size_t MAXHUNK = 32*1024L; /* max. default */
  18.  
  19.     /* CAUTION: use _mallocChunkSize() to tailor to your environment,
  20.             do not make the default too large, as the compiler
  21.             gets screwed on a 1M machine otherwise (stack/heap clash)
  22.      */
  23.  
  24. struct mem_chunk _mchunk_free_list = { VAL_FREE, NULL, 0L };
  25.  
  26. /* flag to control zero'ing of malloc'ed chunks */
  27. static int _ZeroMallocs = 0;
  28.  
  29.  
  30. #if 0
  31. asm(".text; .even; .globl _mlalloc; _mlalloc:"); /* dept of dirty tricks */
  32. #endif
  33.  
  34. void * _malloc(n)
  35. unsigned long n; 
  36. {
  37.   struct mem_chunk *p, *q;
  38.   unsigned long sz;
  39.   extern void *_heapbase;
  40.   extern void _bzero();
  41.  
  42. /* add a mem_chunk to required size and round up */
  43.   n = n + sizeof(struct mem_chunk);
  44.   n = (7 + n) & ~(7L);
  45. /* look for first block big enough in free list */
  46.   p = &_mchunk_free_list;
  47.   q = _mchunk_free_list.next;
  48.  
  49.   while ((q != NULL) && (q->size < n))
  50.     {
  51.     p = q;
  52.     q = q->next;
  53.     }
  54.  
  55. /* if not enough memory, get more from the system */
  56.   if (q == NULL) 
  57.     {
  58.     if ((_heapbase != NULL) || (n > MINHUNK))
  59.         sz = n;
  60.     else {
  61.         sz = MINHUNK;
  62.         if (MINHUNK < MAXHUNK)
  63.             MINHUNK *= 2;
  64.     }
  65.     q = (struct mem_chunk * )_sbrk(sz);
  66.  
  67.     if (((long)q) == -1)         /* can't alloc any more? */
  68.         return(NULL);
  69.  
  70.     p->next = q;
  71.     q->size = sz;
  72.     q->next = NULL;
  73.     q->valid = VAL_FREE;
  74.     }
  75.         
  76.   if (q->size > n + sizeof(struct mem_chunk))
  77.     {                /* split, leave part of free list */
  78.     q->size -= n;
  79.     q = (struct mem_chunk * )(((long) q) + q->size);
  80.     q->size = n;
  81.     q->valid = VAL_ALLOC;
  82.     }
  83.     else
  84.     {                /* just unlink it */
  85.     p->next = q->next;
  86.     q->valid = VAL_ALLOC;
  87.     }
  88.  
  89.   q->next = NULL;    
  90.   q++;    /* hand back ptr to after chunk desc */
  91.   if(_ZeroMallocs != 0)
  92.       _bzero((void *)q, (unsigned long)(n - sizeof(struct mem_chunk)));
  93.   
  94.   return((void * )q);
  95. }
  96.  
  97. void * malloc(n)
  98. size_t n; 
  99. {
  100.   return _malloc((unsigned long) n);
  101. }
  102.  
  103. void free(param)
  104.     void *param;
  105. {
  106.   struct mem_chunk *o, *p, *q, *s;
  107.   struct mem_chunk *r = (struct mem_chunk *) param;
  108.   extern void *_heapbase;
  109.  
  110. /* free(NULL) should do nothing */
  111.   if (r == 0)
  112.      return;
  113.  
  114. /* move back to uncover the mem_chunk */
  115.   r--;            /* there it is! */
  116.  
  117.   if (r->valid != VAL_ALLOC)
  118.     return;
  119.  
  120.   r->valid = VAL_FREE;
  121.  
  122. /* stick it into free list, preserving ascending address order */
  123.   o = NULL;
  124.   p = &_mchunk_free_list;
  125.   q = _mchunk_free_list.next;
  126.   while (q != NULL && q < r) 
  127.     {
  128.     o = p;
  129.     p = q;
  130.     q = q->next;
  131.     }
  132.  
  133. /* merge after if possible */
  134.   s = (struct mem_chunk * )(((long) r) + r->size);
  135.   if (q != NULL && s >= q) 
  136.     {
  137.     assert(s == q);
  138.     r->size += q->size;
  139.     q = q->next;
  140.     s->size = 0;
  141.     s->next = NULL;
  142.     }
  143.   r->next = q;
  144.     
  145. /* merge before if possible, otherwise link it in */
  146.   s = (struct mem_chunk * )(((long) p) + p->size);
  147.   if (s >= r && p != &_mchunk_free_list)
  148.     /* remember: r may be below &_mchunk_free_list in memory */
  149.     {
  150.     assert(s == r);
  151.     p->size += r->size;
  152.     p->next = r->next;
  153.     r->size = 0;
  154.     r->next = NULL;
  155.     s = (struct mem_chunk * )(((long) p) + p->size);
  156.     if (_heapbase != NULL && s >= (struct mem_chunk *) _heapbase) {
  157.       assert(s == (struct mem_chunk *) _heapbase);
  158.       _heapbase = (void *) p;
  159.       _stksize += p->size;
  160.       o->next = NULL;    /* o is always != NULL here */
  161.     }
  162.     }
  163.     else
  164.         {
  165.       s = (struct mem_chunk * )(((long) r) + r->size);
  166.       if (_heapbase != NULL && s >= (struct mem_chunk *) _heapbase) {
  167.         assert(s == (struct mem_chunk *) _heapbase);
  168.         _heapbase = (void *) r;
  169.         _stksize += r->size;
  170.         p->next = NULL;
  171.       } else p->next = r;
  172.     }
  173. }
  174.  
  175. /* realloc() is now defined in realloc.c -- sb */
  176. #if 0
  177.  
  178. #if 0
  179. asm(".text; .even; .globl _relalloc,_realloc; _relalloc: jra _realloc");
  180. #ifdef NDEBUG
  181. static char *__dummy = ""; /* otherwise we get a bra with 0 offset above */
  182. #endif
  183. #endif
  184.  
  185. void * _realloc(_r, n)
  186. void *_r;
  187. unsigned long n;
  188. {
  189.   struct mem_chunk *p, *q, *r = (struct mem_chunk *) _r;
  190.   unsigned long sz;
  191.  
  192. /* obscure features: realloc(NULL,n) is the same as malloc(n)
  193.  *               realloc(p, 0) is the same as free(p)
  194.  */
  195.   if (!r)
  196.     return malloc(n);
  197.   if (n == 0) {
  198.     free(_r);
  199.     return NULL;
  200.   }
  201.   p = r - 1;
  202.   sz = (n + sizeof(struct mem_chunk) + 7) & ~(7L);
  203.  
  204.   if (p->size > sz) 
  205.     {            /* block too big, split in two */
  206.     q = (struct mem_chunk * )(((long) p) + sz);
  207.     q->size = p->size - sz;
  208.         q->valid = VAL_ALLOC;
  209.     free(q + 1);
  210.     p->size = sz;
  211.     }
  212.     else 
  213.   if (p->size < sz)
  214.     {            /* block too small, get new one */
  215.     struct mem_chunk *s, *t;
  216.     q = &_mchunk_free_list;
  217.     t = _mchunk_free_list.next;
  218.     while (t != NULL && t < p)
  219.       {
  220.       q = t;
  221.       t = t->next;
  222.       }
  223.  
  224.     /* merge after if possible */
  225.     s = (struct mem_chunk * )(((long) p) + p->size);
  226.     if (t != NULL && s >= t && p->size + t->size >= sz)
  227.       {
  228.       assert(s == t);
  229.       p->size += t->size;
  230.       q->next = t->next;
  231.       t->size = 0;
  232.       t->next = NULL;
  233.       }
  234.     else
  235.       {
  236.       q = (struct mem_chunk * )malloc(n);
  237.       if (q != NULL)
  238.     {
  239.     n = p->size - sizeof(struct mem_chunk);
  240.     bcopy(r, q, n);
  241.         free(r);    /* free r only if we got a new block */
  242.         }
  243.       r = q;
  244.     }
  245.   }
  246.   /* else current block will do just fine */
  247.   return((void * )r);
  248. }
  249.  
  250. void * realloc(_r, n)
  251. void *_r;
  252. size_t n;
  253. {
  254.   return _realloc(_r, (unsigned long) n);
  255. }
  256.  
  257. #endif /* realloc() */
  258.  
  259. /* calloc() is now defined in calloc.c -- sb */
  260. #if 0
  261.  
  262. #if 0
  263. asm(".text; .even; .globl _clalloc; _clalloc:");
  264. #endif
  265.  
  266. void * _calloc(n, sz)
  267. unsigned long n, sz;
  268. {
  269.   void *r;
  270.   unsigned long total;
  271.   extern void _bzero();
  272.  
  273.   total = n * sz;
  274.   if ((r = _malloc(total)) != NULL) {
  275.     _bzero(r, total);
  276.   }
  277.   return(r);
  278. }
  279.  
  280. void * calloc(n, sz)
  281. size_t n, sz;
  282. {
  283.   return _calloc((unsigned long) n, (unsigned long) sz);
  284. }
  285.  
  286. #endif /* calloc() */
  287.  
  288. /*
  289.  * Set zero block after malloc flag
  290.  */
  291. void _malloczero(yes)
  292. int yes;
  293. {
  294.     _ZeroMallocs = yes;
  295. }
  296.  
  297. /*
  298.  * tune chunk size
  299.  */
  300. void _mallocChunkSize (siz)
  301. size_t siz;
  302. {
  303.     MAXHUNK = MINHUNK = siz;
  304. }
  305.